package cn.fastpay.management.security;

import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * @author freewolf
 */
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private String headerKey;
    private String prefix;
    private String secret;

    public JwtAuthorizationFilter(AuthenticationManager authManager, String secret, String headerKey, String prefix) {
        super(authManager);

        this.headerKey = headerKey;
        this.prefix = prefix;
        this.secret = secret;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
                                    FilterChain chain) throws IOException, ServletException {
        String header = req.getHeader(headerKey);
        if (header == null || !header.startsWith(prefix)) {
            chain.doFilter(req, res);
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);

        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(this.headerKey);
        if (token != null) {
            // parse the token.
            String user = Jwts.parser()
                    .setSigningKey(secret.getBytes())
                    .parseClaimsJws(token.replace(prefix, ""))
                    .getBody()
                    .getSubject();

            List claims = (List) Jwts.parser()
                    .setSigningKey(secret.getBytes())
                    .parseClaimsJws(token.replace(prefix, ""))
                    .getBody().get("claims");

            List<GrantedAuthority> authorities = new ArrayList<>();

            claims.stream().forEach(item -> {
               Map<String, Object> map = (Map<String, Object>)item;
               authorities.add(new SimpleGrantedAuthority(map.get("authority").toString()));
            });

            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, authorities);
            }
            return null;
        }
        return null;
    }
}
